package com.hu.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.hu.adapter.QuestionBuilder;
import com.hu.common.ErrorCode;
import com.hu.common.PageRequest;
import com.hu.common.question.QuestionDto;
import com.hu.constant.QuestionConstans;
import com.hu.constant.UserConstant;
import com.hu.dao.QuestionBankQuestionDao;
import com.hu.dao.QuestionDao;
import com.hu.exception.BusinessException;
import com.hu.exception.ThrowUtils;
import com.hu.pojo.dto.question.QuestionAddRequest;
import com.hu.pojo.dto.question.QuestionQueryRequest;
import com.hu.pojo.dto.question.QuestionUpdateRequest;
import com.hu.pojo.entity.Question;
import com.hu.pojo.entity.QuestionBankQuestion;
import com.hu.pojo.vo.QuestionVO;
import com.hu.service.QuestionService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.aop.framework.AopContext;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author 20272
 * @description 针对表【question(题目)】的数据库操作Service实现
 * @createDate 2024-09-24 22:41:22
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class QuestionServiceImpl implements QuestionService {

    private final QuestionDao questionDao;
    private final QuestionBankQuestionDao questionBankQuestionDao;

/*    @Resource
    private ElasticsearchRestTemplate elasticsearchRestTemplate;*/

    /**
     * 分页获取题目封装
     *
     * @param questionPage
     * @param request
     * @return
     */
    @Override
    public Page<QuestionVO> getQuestionVOPage(Page<Question> questionPage, HttpServletRequest request) {
        List<Question> questionList = questionPage.getRecords();
        Page<QuestionVO> questionVOPage = new Page<>(questionPage.getCurrent(), questionPage.getSize(), questionPage.getTotal());
        if (CollUtil.isEmpty(questionList)) {
            return questionVOPage;
        }
        // 对象列表 => 封装对象列表
        List<QuestionVO> questionVOList = questionList.stream()
                .map(question -> QuestionVO.objToVo(question))
                .collect(Collectors.toList());
        questionVOPage.setRecords(questionVOList);
        return questionVOPage;
    }

    /**
     * 分页获取题目列表
     *
     * @param questionQueryRequest
     * @return
     */
    public Page<Question> listQuestionByPage(QuestionQueryRequest questionQueryRequest) {
        Page<Question> questionPage = questionDao.pages(questionQueryRequest);
        return questionPage;
    }

    /**
     * 批量删除题目
     *
     * @param questionIdList
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void batchDeleteQuestions(List<Long> questionIdList) {
        try {
            // 获取关联数据的ids
            List<Long> questionBankQuestionIds = questionBankQuestionDao.batchIdsByQuestionIds(questionIdList);
            // 然后批量删除
            questionBankQuestionDao.batchDeleteQuestionBankQuestionByIds(questionBankQuestionIds);
            questionDao.batchDeleteQuestionByIds(questionIdList);
        } catch (Exception e) {
            ThrowUtils.throwIf(e != null, ErrorCode.OPERATION_ERROR, "删除题目失败");
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean save(Question question) {
        return questionDao.save(question);
    }

    @Override
    public Question getQuestionById(long questionId) {
        return questionDao.getById(questionId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean deleteByQuestionById(long questionId) {
        Question question = questionDao.getById(questionId);
        ThrowUtils.throwIf(question == null, ErrorCode.NOT_FOUND_ERROR);
        return questionDao.removeById(questionId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateQuestion(QuestionUpdateRequest questionUpdateRequest) {
        List<Long> questionBankId = questionUpdateRequest.getQuestionBankId();
        Question question = QuestionBuilder.builderQuestionUpdateToQuestion(questionUpdateRequest);
        long questionId = question.getId();
        Question source = questionDao.getById(questionId);
        ThrowUtils.throwIf(source == null, ErrorCode.NOT_FOUND_ERROR);
        long userId = StpUtil.getLoginIdAsLong();
        Long createBy = source.getCreateBy();
        List<QuestionBankQuestion> questionBankQuestions = questionBankQuestionDao.queryQuesBankQuesByQuesId(questionId);
        // 全增&& 鉴权
        if (CollectionUtil.isNotEmpty(questionBankId) && CollectionUtil.isNotEmpty(questionBankQuestions)
                && questionBankId.size() == 1 && questionBankQuestions.size() == 1
                && questionBankId.get(0) == QuestionConstans.QUESTION_BANK_DEFAULT && QuestionConstans.QUESTION_BANK_DEFAULT == questionBankQuestions.get(0).getQuestionBankId()
                && userId == createBy) {
            // 普通用户,无需修改所属题库(禁止)
            return questionDao.updateById(question);
        } else {
            // 管理员/有权限者
            if (StpUtil.hasRole(UserConstant.ADMIN_ROLE)
                    && StpUtil.hasPermissionOr(UserConstant.DELETE_PERMISSION, UserConstant.ALL_PERMISSION)) {
                //  全删
                questionBankQuestionDao.deleteQuesBankQuesByQuesId(questionId);
                // 全增 TODO 加锁
                questionBankQuestionDao.addBatchQuestionBankQuestion(questionBankId, questionId);
                return questionDao.updateById(question);
            }
        }
        throw new BusinessException(ErrorCode.NO_AUTH_ERROR);
    }

    @Override
    public Page<QuestionDto> getMyQuestionPage(PageRequest pageRequest) {
        long userId = StpUtil.getLoginIdAsLong();
        long current = pageRequest.getCurrent();
        long size = pageRequest.getPageSize();
        Page<Question> page = new Page<>(current, size);
        questionDao.page(page, questionDao.lambdaQuery().eq(Question::getCreateBy, userId));
        List<Question> questionList = page.getRecords();
        Page<QuestionDto> questionDtoPage = new Page<>(current, size, page.getTotal());
        List<QuestionDto> recordsList = new ArrayList<>();
        if (CollectionUtil.isNotEmpty(questionList)) {
            recordsList = questionList.stream()
                    .map(QuestionBuilder::builderQuestionToQuestionDto)
                    .collect(Collectors.toList());
        }
        questionDtoPage.setRecords(recordsList);
        return questionDtoPage;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean saveQuestion(QuestionAddRequest questionAddRequest) {
        List<Long> questionBankIds = questionAddRequest.getQuestionBankId();
        // 普通题库,普通用户也能添加 TODO 每天限量添加
        if (CollUtil.isNotEmpty(questionBankIds) && questionBankIds.size() == 1 && questionBankIds.contains(QuestionConstans.QUESTION_BANK_DEFAULT)) {
            ((QuestionServiceImpl) AopContext.currentProxy()).saveQuestion(questionAddRequest, questionBankIds);
        } else {
            // 不是普通题库,则需要鉴权
            if (StpUtil.hasRole(UserConstant.ADMIN_ROLE) && StpUtil.hasPermissionOr(UserConstant.DELETE_PERMISSION, UserConstant.ALL_PERMISSION)) {
                ((QuestionServiceImpl) AopContext.currentProxy()).saveQuestion(questionAddRequest, questionBankIds);
            }
        }
        return Boolean.TRUE;
    }

    private void saveQuestion(QuestionAddRequest questionAddRequest, List<Long> questionBankIds) {
        Question question = QuestionBuilder.builderQuestionAddToQuestion(questionAddRequest);
        questionDao.save(question);
        List<QuestionBankQuestion> questionBankQuestions = new ArrayList<>();
        // 批量获取没到题目对应的题库的最大序号 获取题目最大的序号 TODO 使用分布式锁
        Map<Long,Integer> queryQuestionBankQuestionMax = questionBankQuestionDao.queryQuestionBankQuestionMax(questionBankIds);
        //保存关联数据
        for (Long questionBankId : questionBankIds) {
            QuestionBankQuestion questionBankQuestion = new QuestionBankQuestion();
            questionBankQuestion.setQuestionBankId(questionBankId);
            questionBankQuestion.setQuestionId(question.getId());
            questionBankQuestion.setCreateBy(StpUtil.getLoginIdAsLong());
            int number = queryQuestionBankQuestionMax.getOrDefault(questionBankId,0);
            questionBankQuestion.setQuestionOrder(number + 1);
            questionBankQuestions.add(questionBankQuestion);
        }
        questionBankQuestionDao.saveBatch(questionBankQuestions);
    }

/*    @Override
    public Page<Question> searchFromEs(QuestionQueryRequest questionQueryRequest) {
        // 获取参数
        Long id = questionQueryRequest.getId();
        Long notId = questionQueryRequest.getNotId();
        String searchText = questionQueryRequest.getSearchText();
        List<String> tags = questionQueryRequest.getTags();
        Long questionBankId = questionQueryRequest.getQuestionBankId();
        Long userId = questionQueryRequest.getUserId();
        // 注意，ES 的起始页为 0
        int current = questionQueryRequest.getCurrent() - 1;
        int pageSize = questionQueryRequest.getPageSize();
        String sortField = questionQueryRequest.getSortField();
        String sortOrder = questionQueryRequest.getSortOrder();

        // 构造查询条件
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        // 过滤
        boolQueryBuilder.filter(QueryBuilders.termQuery("isDelete", 0));
        if (id != null) {
            boolQueryBuilder.filter(QueryBuilders.termQuery("id", id));
        }
        if (notId != null) {
            boolQueryBuilder.mustNot(QueryBuilders.termQuery("id", notId));
        }
        if (userId != null) {
            boolQueryBuilder.filter(QueryBuilders.termQuery("userId", userId));
        }
        if (questionBankId != null) {
            boolQueryBuilder.filter(QueryBuilders.termQuery("questionBankId", questionBankId));
        }
        // 必须包含所有标签
        if (CollUtil.isNotEmpty(tags)) {
            for (String tag : tags) {
                boolQueryBuilder.filter(QueryBuilders.termQuery("tags", tag));
            }
        }
        // 按关键词检索
        if (StringUtils.isNotBlank(searchText)) {
            // title = '' or content = '' or answer = ''
            boolQueryBuilder.should(QueryBuilders.matchQuery("title", searchText));
            boolQueryBuilder.should(QueryBuilders.matchQuery("content", searchText));
            boolQueryBuilder.should(QueryBuilders.matchQuery("answer", searchText));
            boolQueryBuilder.minimumShouldMatch(1);
        }
        // 排序
        SortBuilder<?> sortBuilder = SortBuilders.scoreSort();
        if (StringUtils.isNotBlank(sortField)) {
            sortBuilder = SortBuilders.fieldSort(sortField);
            sortBuilder.order(CommonConstant.SORT_ORDER_ASC.equals(sortOrder) ? SortOrder.ASC : SortOrder.DESC);
        }
        // 分页
        PageRequest pageRequest = PageRequest.of(current, pageSize);
        // 构造查询
        NativeSearchQuery searchQuery = new NativeSearchQueryBuilder()
                .withQuery(boolQueryBuilder)
                .withPageable(pageRequest)
                .withSorts(sortBuilder)
                .build();
        SearchHits<QuestionEsDTO> searchHits = elasticsearchRestTemplate.search(searchQuery, QuestionEsDTO.class);
        // 复用 MySQL / MyBatis Plus 的分页对象，封装返回结果
        Page<Question> page = new Page<>();
        page.setTotal(searchHits.getTotalHits());
        List<Question> resourceList = new ArrayList<>();
        if (searchHits.hasSearchHits()) {
            List<SearchHit<QuestionEsDTO>> searchHitList = searchHits.getSearchHits();
            for (SearchHit<QuestionEsDTO> questionEsDTOSearchHit : searchHitList) {
                resourceList.add(QuestionEsDTO.dtoToObj(questionEsDTOSearchHit.getContent()));
            }
        }
        page.setRecords(resourceList);
        return page;
    }*/
}




